; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=15 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
;
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

%struct.S = type { i32, double, ptr, i32 }

;    struct S {
;      int a;
;      double b;
;      struct S* c;
;      int written;
;    };
;
;    static const struct S GlobalS = {42, 3.14, 0};
;
;    int testOneFieldGlobalS() {
;      int r = 0;
;      if (GlobalS.a != 42)
;        r += 1;
;      if (GlobalS.b == 3.14)
;        r += 2;
;      if (GlobalS.c)
;        r += 4;
;      return r;
;    }
;
@GlobalS = internal constant %struct.S { i32 42, double 3.140000e+00, ptr null, i32 0 }, align 8

declare void @harmless_use(ptr nocapture readonly) nofree norecurse nosync nounwind readnone willreturn nocallback

;.
; CHECK: @[[GLOBALS:[a-zA-Z0-9_$"\\.-]+]] = internal constant [[STRUCT_S:%.*]] { i32 42, double 3.140000e+00, ptr null, i32 0 }, align 8
;.
define i32 @testOneFieldGlobalS(i32 %cmpx) {
; CHECK: Function Attrs: nofree norecurse nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@testOneFieldGlobalS
; CHECK-SAME: (i32 [[CMPX:%.*]]) #[[ATTR1:[0-9]+]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RMW:%.*]] = atomicrmw add ptr getelementptr inbounds ([[STRUCT_S:%.*]], ptr @GlobalS, i32 0, i32 3), i32 1 monotonic, align 4
; CHECK-NEXT:    [[CXI:%.*]] = cmpxchg ptr getelementptr inbounds ([[STRUCT_S]], ptr @GlobalS, i32 0, i32 3), i32 [[CMPX]], i32 7 acq_rel monotonic, align 4
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    unreachable
; CHECK:       if.end:
; CHECK-NEXT:    br label [[IF_THEN2:%.*]]
; CHECK:       if.then2:
; CHECK-NEXT:    [[ADD3:%.*]] = add nsw i32 0, 2
; CHECK-NEXT:    br label [[IF_END4:%.*]]
; CHECK:       if.end4:
; CHECK-NEXT:    br label [[IF_END7:%.*]]
; CHECK:       if.then5:
; CHECK-NEXT:    unreachable
; CHECK:       if.end7:
; CHECK-NEXT:    ret i32 2
;
entry:
  %i = load i32, ptr @GlobalS, align 8
  call void @harmless_use(ptr @GlobalS)
  %rmw = atomicrmw add ptr getelementptr inbounds (%struct.S, ptr @GlobalS, i32 0, i32 3), i32 1 monotonic, align 4
  %cxi = cmpxchg ptr getelementptr inbounds (%struct.S, ptr @GlobalS, i32 0, i32 3), i32 %cmpx, i32 7 acq_rel monotonic
  %cmp = icmp ne i32 %i, 42
  br i1 %cmp, label %if.then, label %if.end

if.then:                                          ; preds = %entry
  %add = add nsw i32 0, 1
  br label %if.end

if.end:                                           ; preds = %if.then, %entry
  %r.0 = phi i32 [ %add, %if.then ], [ 0, %entry ]
  %i1 = load double, ptr getelementptr inbounds (%struct.S, ptr @GlobalS, i32 0, i32 1), align 8
  %cmp1 = fcmp oeq double %i1, 3.140000e+00
  br i1 %cmp1, label %if.then2, label %if.end4

if.then2:                                         ; preds = %if.end
  %add3 = add nsw i32 %r.0, 2
  br label %if.end4

if.end4:                                          ; preds = %if.then2, %if.end
  %r.1 = phi i32 [ %add3, %if.then2 ], [ %r.0, %if.end ]
  %i2 = load ptr, ptr getelementptr inbounds (%struct.S, ptr @GlobalS, i32 0, i32 2), align 8
  %tobool = icmp ne ptr %i2, null
  br i1 %tobool, label %if.then5, label %if.end7

if.then5:                                         ; preds = %if.end4
  %add6 = add nsw i32 %r.1, 4
  br label %if.end7

if.end7:                                          ; preds = %if.then5, %if.end4
  %r.2 = phi i32 [ %add6, %if.then5 ], [ %r.1, %if.end4 ]
  ret i32 %r.2
}

define i32 @testOneFieldGlobalS_type_mismatch() {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@testOneFieldGlobalS_type_mismatch
; CHECK-SAME: () #[[ATTR2:[0-9]+]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[IF_THEN:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 0, 1
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.end:
; CHECK-NEXT:    br label [[IF_END4:%.*]]
; CHECK:       if.then2:
; CHECK-NEXT:    unreachable
; CHECK:       if.end4:
; CHECK-NEXT:    br label [[IF_END7:%.*]]
; CHECK:       if.then5:
; CHECK-NEXT:    unreachable
; CHECK:       if.end7:
; CHECK-NEXT:    ret i32 1
;
entry:
  %i = load double, ptr @GlobalS, align 8
  %ic = fptosi double %i to i32
  %cmp = icmp ne i32 %ic, 42
  br i1 %cmp, label %if.then, label %if.end

if.then:                                          ; preds = %entry
  %add = add nsw i32 0, 1
  br label %if.end

if.end:                                           ; preds = %if.then, %entry
  %r.0 = phi i32 [ %add, %if.then ], [ 0, %entry ]
  %i1 = load i64, ptr getelementptr inbounds (%struct.S, ptr @GlobalS, i32 0, i32 1), align 8
  %i1c = sitofp i64 %i1 to double
  %cmp1 = fcmp oeq double %i1c, 3.140000e+00
  br i1 %cmp1, label %if.then2, label %if.end4

if.then2:                                         ; preds = %if.end
  %add3 = add nsw i32 %r.0, 2
  br label %if.end4

if.end4:                                          ; preds = %if.then2, %if.end
  %r.1 = phi i32 [ %add3, %if.then2 ], [ %r.0, %if.end ]
  %i2 = load i64, ptr getelementptr inbounds (%struct.S, ptr @GlobalS, i32 0, i32 2), align 8
  %i2c = inttoptr i64 %i2 to ptr
  %tobool = icmp ne ptr %i2c, null
  br i1 %tobool, label %if.then5, label %if.end7

if.then5:                                         ; preds = %if.end4
  %add6 = add nsw i32 %r.1, 4
  br label %if.end7

if.end7:                                          ; preds = %if.then5, %if.end4
  %r.2 = phi i32 [ %add6, %if.then5 ], [ %r.1, %if.end4 ]
  ret i32 %r.2
}

define i32 @testOneFieldGlobalS_byte_offset_wrong() {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@testOneFieldGlobalS_byte_offset_wrong
; CHECK-SAME: () #[[ATTR2]] {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[IF_THEN:%.*]]
; CHECK:       if.then:
; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 0, 1
; CHECK-NEXT:    br label [[IF_END:%.*]]
; CHECK:       if.end:
; CHECK-NEXT:    [[I1:%.*]] = load double, ptr getelementptr (double, ptr @GlobalS, i32 3), align 8
; CHECK-NEXT:    [[CMP1:%.*]] = fcmp oeq double [[I1]], 3.140000e+00
; CHECK-NEXT:    br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END4:%.*]]
; CHECK:       if.then2:
; CHECK-NEXT:    [[ADD3:%.*]] = add nsw i32 1, 2
; CHECK-NEXT:    br label [[IF_END4]]
; CHECK:       if.end4:
; CHECK-NEXT:    [[R_1:%.*]] = phi i32 [ [[ADD3]], [[IF_THEN2]] ], [ 1, [[IF_END]] ]
; CHECK-NEXT:    br label [[IF_THEN5:%.*]]
; CHECK:       if.then5:
; CHECK-NEXT:    [[ADD6:%.*]] = add nsw i32 [[R_1]], 4
; CHECK-NEXT:    br label [[IF_END7:%.*]]
; CHECK:       if.end7:
; CHECK-NEXT:    ret i32 [[ADD6]]
;
entry:
  %i = load i32, ptr getelementptr (i32, ptr @GlobalS, i32 1), align 8
  %cmp = icmp ne i32 %i, 42
  br i1 %cmp, label %if.then, label %if.end

if.then:                                          ; preds = %entry
  %add = add nsw i32 0, 1
  br label %if.end

if.end:                                           ; preds = %if.then, %entry
  %r.0 = phi i32 [ %add, %if.then ], [ 0, %entry ]
  %i1 = load double, ptr getelementptr (double, ptr @GlobalS, i32 3), align 8
  %cmp1 = fcmp oeq double %i1, 3.140000e+00
  br i1 %cmp1, label %if.then2, label %if.end4

if.then2:                                         ; preds = %if.end
  %add3 = add nsw i32 %r.0, 2
  br label %if.end4

if.end4:                                          ; preds = %if.then2, %if.end
  %r.1 = phi i32 [ %add3, %if.then2 ], [ %r.0, %if.end ]
  %i2 = load ptr, ptr getelementptr (ptr, ptr @GlobalS, i32 11), align 8
  %tobool = icmp ne ptr %i2, null
  br i1 %tobool, label %if.then5, label %if.end7

if.then5:                                         ; preds = %if.end4
  %add6 = add nsw i32 %r.1, 4
  br label %if.end7

if.end7:                                          ; preds = %if.then5, %if.end4
  %r.2 = phi i32 [ %add6, %if.then5 ], [ %r.1, %if.end4 ]
  ret i32 %r.2
}
;.
; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree norecurse nosync nounwind willreturn memory(none) }
; CHECK: attributes #[[ATTR1]] = { nofree norecurse nounwind willreturn memory(none) }
; CHECK: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind willreturn memory(none) }
;.
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CGSCC: {{.*}}
; TUNIT: {{.*}}
